package com.cuteserver.client;

/*
This file is part of Cute-Client.

Cute-Client is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Cute-Client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Cute-Client.  If not, see <http://www.gnu.org/licenses/>.
*/

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * CSClient object is the representation of a connection with a cute-server.
 * It allows to open or join sessions on the server.
 * 
 * @author Aurelien Deharbe
 * @version 1.0
 */
public class CSClient {

	/**
	 * The socket connexion with the server
	 */
	private Socket serversocket = null;
	
	/**
	 * The writer in the socket
	 */
	private PrintWriter writer = null;
	
	/**
	 * The reader from the socket
	 */
	private BufferedReader reader = null;
	
	/**
	 * Construct and connect a client
	 * @param host cute-server host
	 * @param port cute-server port
	 * @throws CSException If there is connection problem
	 */
	public CSClient(String host, int port) throws CSException
	{
		try {
			this.serversocket = new Socket(host, port);
		} catch(UnknownHostException e) {
			throw new CSException(CSException.UNKNOWN_HOST);
		} catch(IOException e) {
			throw new CSException(CSException.CONNEXION);
		}
		
		try {
			this.serversocket.setReuseAddress(true);
		} catch(SocketException e) {
			throw new CSException(CSException.UNKNOWN_ERROR);
		}
		
		try {
			InputStream is = serversocket.getInputStream();
			InputStreamReader isr = new InputStreamReader(is);
			reader = new BufferedReader(isr);
			
			OutputStream os = serversocket.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os);
			BufferedWriter bw = new BufferedWriter(osw);
			writer = new PrintWriter(bw);
		} catch(IOException e) {
			throw new CSException(CSException.CONNEXION);
		}
	}
	
	/**
	 * Create a new session on the cute-server
	 * @param sessid The unique id of the session
	 * @return The session object
	 * @throws CSException If there is connection problem,
	 * or if sessid is already used attribute by the server
	 */
	public CSSession newSession(String sessid) throws CSException
	{
		return this.accessSession("QSSessionNew(" + sessid + ")\n");
	}
	
	/**
	 * Join an existing session on the cute-server
	 * @param sessid The unique id of the session
	 * @return The session object
	 * @throws CSException If there is connection problem,
	 * or if sessid is not an existing session id on the server
	 */
	public CSSession joinSession(String sessid) throws CSException
	{
		return this.accessSession("QSSessionJoin(" + sessid + ")\n");
	}
	
	/**
	 * Effectively connect to a cute-server session
	 * @param cmd The command required to join or create a session
	 * @return The session object
	 * @throws CSException If there is connexion problem
	 */
	private CSSession accessSession(String cmd) throws CSException
	{
		if (serversocket == null) {
			throw new CSException(CSException.BAD_INITIALIZATION);
		}
		
		try {
			writer.write(cmd);
			writer.flush();
			reader.readLine();
		} catch(IOException e) {
			throw new CSException(CSException.CONNEXION);
		}
		CSSession session = new CSSession();
		int sessport = session.getPort();
		try {
			writer.write("QSSessionPort(" + sessport + ")\n");
			writer.flush();
			reader.readLine();
			session.accept();
		} catch(IOException e) {
			throw new CSException(CSException.CONNEXION);
		}
		
		return session;
	}
}
